/* main.c - Application main entry point */

/*
 * Copyright (c) 2017 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdio.h>
#include <string.h>
#include <aos/aos.h>
#include <aos/kernel.h>

#include <misc/printk.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/mesh.h>

#include "mesh.h"
#include "net.h"
#include "transport.h"
#include "bluetooth/mesh/cfg_cli.h"

#define CID_INTEL 0x0002

#define NODE_ADDR 0x000f
#if !defined(NODE_ADDR)
#define NODE_ADDR 0x0b0c
#endif

#define GROUP_ADDR 0xc000
#define PUBLISHER_ADDR  0x000f

#define OP_VENDOR_BUTTON BT_MESH_MODEL_OP_3(0x00, CID_INTEL)

static const u8_t net_key[16] = {
    0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
    0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
};
static const u8_t dev_key[16] = {
    0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
    0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
};
static const u8_t app_key[16] = {
    0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
    0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
};
static u16_t net_idx;
static const u16_t app_idx;
static const u32_t iv_index;
static u8_t flags;
static u16_t addr = NODE_ADDR;
static u32_t seq;

static void heartbeat(u8_t hops, u16_t feat)
{
    printk("aos ble mesh, hello world\r\n");
}

static struct bt_mesh_cfg_srv cfg_srv = {
#if defined(CONFIG_BOARD_BBC_MICROBIT)
    .relay = BT_MESH_RELAY_ENABLED,
    .beacon = BT_MESH_BEACON_DISABLED,
#else
    .relay = BT_MESH_RELAY_ENABLED,
    .beacon = BT_MESH_BEACON_ENABLED,
#endif
#if defined(CONFIG_BT_MESH_GATT_PROXY)
    .gatt_proxy = BT_MESH_GATT_PROXY_ENABLED,
#else
    .gatt_proxy = BT_MESH_GATT_PROXY_NOT_SUPPORTED,
#endif
    .frnd = BT_MESH_FRIEND_NOT_SUPPORTED,
    .default_ttl = 7,

    /* 3 transmissions with 20ms interval */
    .net_transmit = BT_MESH_TRANSMIT(2, 20),
    .relay_retransmit = BT_MESH_TRANSMIT(3, 20),

    .hb_sub.func = heartbeat,
};

static struct bt_mesh_cfg_cli cfg_cli = {
};

static void attention_on(struct bt_mesh_model *model)
{
    printk("attention_on()\n");
}

static void attention_off(struct bt_mesh_model *model)
{
    printk("attention_off()\n");
}

static const struct bt_mesh_health_srv_cb health_srv_cb = {
    .attn_on = attention_on,
    .attn_off = attention_off,
};

static struct bt_mesh_health_srv health_srv = {
    .cb = &health_srv_cb,
};

static struct bt_mesh_model_pub health_pub = {
    .msg  = BT_MESH_HEALTH_FAULT_MSG(0),
};

static struct bt_mesh_model root_models[] = {
    BT_MESH_MODEL_CFG_SRV(&cfg_srv),
    BT_MESH_MODEL_CFG_CLI(&cfg_cli),
    BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
};

static struct bt_mesh_model vnd_models[] = {
};

static struct bt_mesh_elem elements[] = {
    BT_MESH_ELEM(0, root_models, vnd_models),
};

static const struct bt_mesh_comp comp = {
    .cid = CID_INTEL,
    .elem = elements,
    .elem_count = ARRAY_SIZE(elements),
};

static void configure(void)
{
    printk("Configuring...\n");

    /* Add Application Key */
    bt_mesh_cfg_app_key_add(net_idx, addr, net_idx, app_idx, app_key, NULL);

    /* Bind to Health model */
    bt_mesh_cfg_mod_app_bind(net_idx, addr, addr, app_idx,
                             BT_MESH_MODEL_ID_HEALTH_SRV, NULL);

#if NODE_ADDR == PUBLISHER_ADDR
    {
        struct bt_mesh_cfg_hb_pub pub = {
            .dst = GROUP_ADDR,
            .count = 0xff,
            .period = 0x05,
            .ttl = 0x07,
            .feat = 0,
            .net_idx = net_idx,
        };

        bt_mesh_cfg_hb_pub_set(net_idx, addr, &pub, NULL);
        printk("Publishing heartbeat messages\n");
    }
#else
    {
        struct bt_mesh_cfg_hb_sub sub = {
            .src = PUBLISHER_ADDR,
            .dst = GROUP_ADDR,
            .period = 0x10,
        };

        bt_mesh_cfg_hb_sub_set(net_idx, addr, &sub, NULL);
        printk("Subscribing to heartbeat messages\n");
    }
#endif

    printk("Configuration complete\n");
}

static const u8_t dev_uuid[16] = { 0xdd, 0xde };

static int output_number(bt_mesh_output_action_t action, uint32_t number)
{
    printk("OOB Number: %u\n", number);
    return 0;
}

static void prov_complete(u16_t netidx, u16_t laddr)
{
}

static void prov_reset(void)
{
    bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);
}

static const struct bt_mesh_prov prov = {
    .uuid = dev_uuid,
    .output_size = 4,
    .output_actions = BT_MESH_DISPLAY_NUMBER,
    .output_number = output_number,
    .complete = prov_complete,
    .reset = prov_reset,
};

static void bt_ready(int err)
{
    if (err) {
        printk("Bluetooth init failed (err %d)\n", err);
        return;
    }

    printk("Bluetooth initialized\n");

    err = bt_mesh_init(&prov, &comp);
    if (err) {
        printk("Initializing mesh failed (err %d)\n", err);
        return;
    }

    printk("Mesh initialized\n");

    err = bt_mesh_provision(net_key, net_idx, flags, iv_index, seq, addr,
                            dev_key);
    if (err) {
        printk("Provisioning failed (err %d)\n", err);
        return;
    }

    printk("Provisioning completed\n");

    configure();
}

extern int hci_driver_init(void);
void blemesh_sample(void)
{
    int err;

    printk("Initializing...\n");
    printk("Unicast address: 0x%04x, seq 0x%06x\n", addr, seq);

    hci_driver_init();
    /* Initialize the Bluetooth Subsystem */
    err = bt_enable(bt_ready);
    if (err) {
        printk("Bluetooth init failed (err %d)\n", err);
    }
}

static void app_delayed_action(void *arg)
{
    blemesh_sample();
}

int application_start(int argc, char **argv)
{
    aos_post_delayed_action(1000, app_delayed_action, NULL);
    aos_loop_run();
    return 0;
}
